package fr.bordeaux1.planingdesetudiants.controler.db;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import fr.bordeaux1.planingdesetudiants.controler.CreneauFormater;
import fr.bordeaux1.planingdesetudiants.model.AccumulateurErreur;
import fr.bordeaux1.planingdesetudiants.model.Cours;
import fr.bordeaux1.planingdesetudiants.model.Enseignant;
import fr.bordeaux1.planingdesetudiants.model.Etudiant;
import fr.bordeaux1.planingdesetudiants.model.Groupe;
import fr.bordeaux1.planingdesetudiants.model.Ue;

class DBPlaningDesEtudiantsSqlite implements IDBPlaningDesEtudiants {
	private Connection conn;

	// on garde les requetes préparées en mémoire
	PreparedStatement rechercheNumeroEtudiant, insertionEtudiant,
			rechercheLiaisonUeEtudiant, creationLiaisonUeEtudiant,
			rechercheCodeUe, insertionUe, listeEtudiants, listeUes,chargerUe,
			listeUesEtudiant, listeEtudiantsUe, listeEtudiantsSansGroupeUe, retirerEtudiantUe,retirerEtudiantsTousGroupesUe,
			retirerEtudiantToutesUe, retirerEtudiantTousGroupes,
			supprimerEtudiant, ajouterCours, modifierCours,retirerTousGroupesCours,
			supprimerCours,listerCours,ajouterEnseignant,modifierEnseignant,
			retirerEnseignantTousCours,supprimerEnseignant,	listeEnseignant,
			ajouterGroupe,retirerGroupeTousCours,retirerGroupeTousEtudiants,supprimerGroupe,
			listeGroupes,ajouterGroupeAuCours,retirerGroupeDeCours,listerGroupesDeCours,
			listerCoursDeGroupe,ajouterEtudiantAuGroupe,retirerEtudiantDeGroupe,listerEtudiantsDeGroupe
			,listerGroupesEtudiant,enseignantDeCours,listerCoursEnseignant,listerGroupeDeUe,modifierCreneauCours,recupererGroupeParDefaut;


	// constructeur masqué l'exterieur du package
	DBPlaningDesEtudiantsSqlite(String filename) throws Exception {
		Class.forName("org.sqlite.JDBC");
		conn = DriverManager.getConnection("jdbc:sqlite:/" + filename);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * fr.bordeaux1.planingdesetudiants.controler.db.DBPlaningDesEtudiants#ajouterUe
	 * (fr.bordeaux1.planingdesetudiants.model.Ue, boolean)
	 */
	@Override
	public void ajouterUe(Ue ue) throws SQLException {
		
		if (insertionUe == null)
			insertionUe = conn
					.prepareStatement("INSERT INTO ues (code_ue,libele_ue) VALUES (?,?)");
		
		
		
		insertionUe.setString(1, ue.getCode());
		insertionUe.setString(2, ue.getLibelle());

		insertionUe.executeUpdate();
		

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see fr.bordeaux1.planingdesetudiants.controler.db.DBPlaningDesEtudiants#
	 * ajouterEtudiant
	 * (fr.bordeaux1.planingdesetudiants.model.Etudiant)
	 */
	
	@Override
	public void ajouterEtudiant(Etudiant etudiant) throws SQLException {

		if (insertionEtudiant == null)
			insertionEtudiant = conn
					.prepareStatement("INSERT INTO etudiants (numero_etudiant,nom_etudiant,prenom_etudiant) VALUES (?,?,?)");

		insertionEtudiant.setInt(1, etudiant.getNumero());
		insertionEtudiant.setString(2, etudiant.getNom());
		insertionEtudiant.setString(3, etudiant.getPrenom());
		insertionEtudiant.executeUpdate();
		
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see fr.bordeaux1.planingdesetudiants.controler.db.DBPlaningDesEtudiants#
	 * ajouterEtudiantSiInexistant
	 * (fr.bordeaux1.planingdesetudiants.model.Etudiant)
	 */
	
	public void ajouterEtudiantSiInexistant(Etudiant etudiant)
			throws SQLException {

		if (rechercheNumeroEtudiant == null)
			rechercheNumeroEtudiant = conn
					.prepareStatement("SELECT numero_etudiant FROM etudiants WHERE numero_etudiant=?");

		rechercheNumeroEtudiant.setInt(1, etudiant.getNumero());
		ResultSet rs = rechercheNumeroEtudiant.executeQuery();
		boolean existe = rs.next();
		rs.close();
		if (!existe)
			ajouterEtudiant(etudiant);
		
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see fr.bordeaux1.planingdesetudiants.controler.db.DBPlaningDesEtudiants#
	 * lierEtudiantEtUe(fr.bordeaux1.planingdesetudiants.model.Ue,
	 * fr.bordeaux1.planingdesetudiants.model.Etudiant, boolean)
	 */
	@Override
	public void ajouterEtudiantAUe(Ue ue, Etudiant etudiant) throws SQLException {
		
		if (creationLiaisonUeEtudiant == null)
			creationLiaisonUeEtudiant = conn
					.prepareStatement("INSERT INTO ues_etudiants (numero_etudiant,code_ue) VALUES (?,?)");

		creationLiaisonUeEtudiant.setInt(1, etudiant.getNumero());
		creationLiaisonUeEtudiant.setString(2, ue.getCode());

		creationLiaisonUeEtudiant.executeUpdate();
		
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see fr.bordeaux1.planingdesetudiants.controler.db.DBPlaningDesEtudiants#
	 * listerEtudiants()
	 */
	@Override
	public List<Etudiant> listerEtudiants() throws SQLException {
		List<Etudiant> etus = new ArrayList<Etudiant>();
		if (listeEtudiants == null)
			listeEtudiants = conn
					.prepareStatement("SELECT numero_etudiant,nom_etudiant,prenom_etudiant FROM etudiants ORDER BY lower(nom_etudiant)");

		ResultSet rs = listeEtudiants.executeQuery();
		while (rs.next()) {
			Etudiant etu = new Etudiant();
			etu.setNumero(rs.getInt(1));
			etu.setNom(rs.getString(2));
			etu.setPrenom(rs.getString(3));
			etus.add(etu);
		}
		rs.close();
		return etus;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * fr.bordeaux1.planingdesetudiants.controler.db.DBPlaningDesEtudiants#listerUes
	 * ()
	 */
	@Override
	public List<Ue> listerUes() throws SQLException {
		List<Ue> ues = new ArrayList<Ue>();
		if (listeUes == null)
			listeUes = conn
					.prepareStatement("SELECT code_ue,libele_ue FROM ues ORDER BY code_ue");

		ResultSet rs = listeUes.executeQuery();
		while (rs.next()) {
			Ue ue = new Ue();
			ue.setCode(rs.getString(1));
			ue.setLibelle(rs.getString(2));
			ues.add(ue);
		}
		rs.close();
		return ues;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see fr.bordeaux1.planingdesetudiants.controler.db.DBPlaningDesEtudiants#
	 * listerUesEtudiant(fr.bordeaux1.planingdesetudiants.model.Etudiant)
	 */
	@Override
	public List<Ue> listerUesEtudiant(Etudiant etu) throws SQLException {
		List<Ue> ues = new ArrayList<Ue>();
		if (listeUesEtudiant == null)
			listeUesEtudiant = conn
					.prepareStatement("SELECT ues.code_ue,ues.libele_ue FROM ues JOIN ues_etudiants ON ues.code_ue=ues_etudiants.code_ue WHERE ues_etudiants.numero_etudiant=? ORDER BY ues.code_ue");

		listeUesEtudiant.setInt(1, etu.getNumero());

		ResultSet rs = listeUesEtudiant.executeQuery();
		while (rs.next()) {
			Ue ue = new Ue();
			ue.setCode(rs.getString(1));
			ue.setLibelle(rs.getString(2));
			ues.add(ue);
		}
		rs.close();
		return ues;
	}

	// visible uniquement dans le package
	Connection getConnection() {
		return conn;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see fr.bordeaux1.planingdesetudiants.controler.db.DBPlaningDesEtudiants#
	 * beginTransaction()
	 */
	@Override
	public void beginTransaction() throws SQLException {
		conn.setAutoCommit(false);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see fr.bordeaux1.planingdesetudiants.controler.db.DBPlaningDesEtudiants#
	 * endTransaction()
	 */
	@Override
	public void endTransaction() throws SQLException {
		conn.commit();
		conn.setAutoCommit(true);
	}

	@Override
	public List<Etudiant> listerEtudiantsUe(Ue ue) throws SQLException {
		List<Etudiant> etus = new ArrayList<Etudiant>();
		if (listeEtudiantsUe == null)
			listeEtudiantsUe = conn
					.prepareStatement("SELECT etudiants.numero_etudiant,nom_etudiant,prenom_etudiant FROM etudiants JOIN ues_etudiants ON etudiants.numero_etudiant=ues_etudiants.numero_etudiant WHERE ues_etudiants.code_ue=? ORDER BY etudiants.nom_etudiant");

		listeEtudiantsUe.setString(1, ue.getCode());

		ResultSet rs = listeEtudiantsUe.executeQuery();

		while (rs.next()) {
			Etudiant etu = new Etudiant();
			etu.setNumero(rs.getInt(1));
			etu.setNom(rs.getString(2));
			etu.setPrenom(rs.getString(3));
			etus.add(etu);
		}
		rs.close();
		return etus;
	}

	@Override
	public List<Etudiant> listerEtudiantsSansGroupeUe(Ue ue) throws SQLException {
		List<Etudiant> etus = new ArrayList<Etudiant>();
		if (listeEtudiantsSansGroupeUe == null)
			listeEtudiantsSansGroupeUe = conn
					.prepareStatement("SELECT etudiants.numero_etudiant,nom_etudiant,prenom_etudiant FROM etudiants JOIN ues_etudiants ON etudiants.numero_etudiant=ues_etudiants.numero_etudiant WHERE ues_etudiants.code_ue=? AND etudiants.numero_etudiant AND etudiants.numero_etudiant NOT IN (SELECT numero_etudiant FROM groupes_etudiants JOIN groupes ON groupes_etudiants.id_groupe = groupes.id_groupe WHERE groupes.code_ue = ?) ORDER BY etudiants.nom_etudiant");

		listeEtudiantsSansGroupeUe.setString(1, ue.getCode());
		listeEtudiantsSansGroupeUe.setString(2, ue.getCode());

		ResultSet rs = listeEtudiantsSansGroupeUe.executeQuery();

		while (rs.next()) {
			Etudiant etu = new Etudiant();
			etu.setNumero(rs.getInt(1));
			etu.setNom(rs.getString(2));
			etu.setPrenom(rs.getString(3));
			etus.add(etu);
		}
		rs.close();
		return etus;
	}

	@Override
	public void retirerEtudiantUe(Ue eu, Etudiant etu) throws SQLException {
		if(retirerEtudiantsTousGroupesUe == null)
			retirerEtudiantsTousGroupesUe = conn.prepareStatement("DELETE FROM groupes_etudiants WHERE numero_etudiant=? AND id_groupe IN (SELECT id_groupe FROM groupes WHERE code_ue=?)");
		retirerEtudiantsTousGroupesUe.setString(2, eu.getCode());
		retirerEtudiantsTousGroupesUe.setInt(1, etu.getNumero());
		retirerEtudiantsTousGroupesUe.executeUpdate();
		
		if (retirerEtudiantUe == null)
			retirerEtudiantUe = conn
					.prepareStatement("DELETE FROM ues_etudiants WHERE code_ue=? AND numero_etudiant=?");

		
		retirerEtudiantUe.setString(1, eu.getCode());
		retirerEtudiantUe.setInt(2, etu.getNumero());

		retirerEtudiantUe.executeUpdate();

	}

	@Override
	public void supprimerEtudiant(Etudiant etu) throws SQLException {

		// enlever l'étudiant de toutes les UE
		if (retirerEtudiantToutesUe == null) {
			retirerEtudiantToutesUe = conn
					.prepareStatement("DELETE FROM ues_etudiants WHERE numero_etudiant=?");
		}
		retirerEtudiantToutesUe.setInt(1, etu.getNumero());
		retirerEtudiantToutesUe.executeUpdate();

		// enlever l'étudiant de tous les groupes
		if (retirerEtudiantTousGroupes == null) {
			retirerEtudiantTousGroupes = conn
					.prepareStatement("DELETE FROM groupes_etudiants WHERE numero_etudiant=?");
		}
		retirerEtudiantTousGroupes.setInt(1, etu.getNumero());
		retirerEtudiantTousGroupes.executeUpdate();

		// supprimer l'étudiant
		if (supprimerEtudiant == null) {
			supprimerEtudiant = conn
					.prepareStatement("DELETE FROM etudiants WHERE numero_etudiant=?");
		}
		supprimerEtudiant.setInt(1, etu.getNumero());
		supprimerEtudiant.executeUpdate();

	}

	@Override
	public void ajouterCours(Cours cours) throws SQLException {
		if (ajouterCours == null) {
			ajouterCours = conn
					.prepareStatement("INSERT INTO cours (type_cours,code_ue,id_enseignant,creneau_cours,salle) VALUES (?,?,?,?,?);");
		}
		ajouterCours.setString(1, cours.getType());
		ajouterCours.setString(2, cours.getCodeUe());
		if (cours.getIdEnseignant() == 0)
			ajouterCours.setNull(3, java.sql.Types.INTEGER);
		else
			ajouterCours.setInt(3, cours.getIdEnseignant());
		ajouterCours.setInt(4, cours.getCreneau());
		ajouterCours.setString(5, cours.getSalle());

		ajouterCours.executeUpdate();

		ResultSet rs = ajouterCours.getGeneratedKeys();
		rs.next();
		cours.setId(rs.getInt(1));
		rs.close();
	}

	@Override
	public void modifierCours(Cours cours) throws SQLException {
		if (modifierCours == null) {
			modifierCours = conn
					.prepareStatement("UPDATE cours SET type_cours=?,code_ue=?,id_enseignant=?,creneau_cours=?,salle=? WHERE id_cours=?");
		}
		modifierCours.setString(1, cours.getType());
		modifierCours.setString(2, cours.getCodeUe());
		modifierCours.setInt(3, cours.getIdEnseignant());
		modifierCours.setInt(4, cours.getCreneau());
		modifierCours.setString(5, cours.getSalle());

		modifierCours.setInt(6, cours.getId());
		
		modifierCours.executeUpdate();
	}

	@Override
	public void supprimerCours(Cours cours) throws SQLException {
		if(retirerTousGroupesCours==null)
			retirerTousGroupesCours = conn.prepareStatement("DELETE FROM cours_groupes WHERE id_cours=?");
		retirerTousGroupesCours.setInt(1, cours.getId());
		retirerTousGroupesCours.executeUpdate();
		
		if(supprimerCours==null)
			supprimerCours = conn.prepareStatement("DELETE FROM cours WHERE id_cours=?");
		supprimerCours.setInt(1, cours.getId());
		supprimerCours.executeUpdate();
		
	}

	@Override
	public List<Cours> listerCours() throws SQLException {
		if(listerCours==null)
			listerCours = conn.prepareStatement("SELECT id_cours,type_cours,code_ue,id_enseignant,creneau_cours,salle FROM cours");
		
		List<Cours> courss = new ArrayList<Cours>(40);
		ResultSet rs = listerCours.executeQuery();
		
		while (rs.next()) {
			Cours cours = new Cours();
			cours.setId(rs.getInt(1));
			cours.setType(rs.getString(2));
			cours.setCodeUe(rs.getString(3));
			cours.setIdEnseignant(rs.getInt(4));
			if (rs.wasNull())
				cours.setIdEnseignant(0);
			cours.setCreneau(rs.getInt(5));
			cours.setSalle(rs.getString(6));
			courss.add(cours);
		}
		rs.close();
		return courss;
	}

	@Override
	public void ajouterEnseignant(Enseignant enseignant) throws SQLException {
		if(ajouterEnseignant==null)
			ajouterEnseignant = conn.prepareStatement("INSERT INTO enseignants (nom_enseignant,prenom_enseignant,disponibilite_enseignant) VALUES (?,?,?)");
		ajouterEnseignant.setString(1, enseignant.getNom());
		ajouterEnseignant.setString(2, enseignant.getPrenom());
		ajouterEnseignant.setString(3, new String(enseignant.getDisponibilite()));

		ajouterEnseignant.executeUpdate();

		ResultSet rs = ajouterEnseignant.getGeneratedKeys();
		rs.next();
		enseignant.setId(rs.getInt(1));
		rs.close();
		
	}

	@Override
	public void modifierEnseignant(Enseignant enseignant) throws SQLException {
		if(modifierEnseignant==null)
			modifierEnseignant = conn.prepareStatement("UPDATE enseignants SET nom_enseignant=?,prenom_enseignant=?,disponibilite_enseignant=? WHERE id_enseignant=?");
		modifierEnseignant.setString(1, enseignant.getNom());
		modifierEnseignant.setString(2, enseignant.getPrenom());
		modifierEnseignant.setString(3, new String(enseignant.getDisponibilite()));
		modifierEnseignant.setInt(4, enseignant.getId());
		
		modifierEnseignant.executeUpdate();
		
	}

	@Override
	public void supprimerEnseignant(Enseignant enseignant) throws SQLException {
		//enlever l'enseignant de tous les cours
		if(retirerEnseignantTousCours==null)
			retirerEnseignantTousCours = conn.prepareStatement("UPDATE cours SET id_enseignant=-1 WHERE id_enseignant=?");
		
		retirerEnseignantTousCours.setInt(1, enseignant.getId());
		retirerEnseignantTousCours.executeUpdate();
					
		if(supprimerEnseignant==null){
			supprimerEnseignant=conn.prepareStatement("DELETE FROM enseignants WHERE id_enseignant=?");
		}
		supprimerEnseignant.setInt(1, enseignant.getId());
		supprimerEnseignant.executeUpdate();
	}

	@Override
	public List<Enseignant> listerEnseignant() throws SQLException {
		if(listeEnseignant==null)
			listeEnseignant = conn.prepareStatement("SELECT id_enseignant,nom_enseignant,prenom_enseignant,disponibilite_enseignant FROM enseignants");
		ResultSet rs = listeEnseignant.executeQuery();
		
		List<Enseignant> enseignants = new ArrayList<Enseignant>(30);
		
		while(rs.next()){
			Enseignant ens = new Enseignant();
			ens.setId(rs.getInt(1));
			ens.setNom(rs.getString(2));
			ens.setPrenom(rs.getString(3));
			ens.setDisponibilite(rs.getString(4).toCharArray());
			enseignants.add(ens);
		}
		rs.close();
		return enseignants;
	}

	@Override
	public void ajouterGroupe(Groupe groupe) throws SQLException {
		if(ajouterGroupe==null)
			ajouterGroupe = conn.prepareStatement("INSERT INTO groupes (nom_groupe,code_ue) VALUES (?,?)");
		
		ajouterGroupe.setString(1,groupe.getNom());
		ajouterGroupe.setString(2, groupe.getCodeUe());
		
		ajouterGroupe.executeUpdate();

		ResultSet rs = ajouterGroupe.getGeneratedKeys();
		rs.next();
		groupe.setId(rs.getInt(1));
		rs.close();
		
		
	}

	@Override
	public void supprimerGroupe(Groupe groupe) throws SQLException {
		//supprimer le groupe de tous les cours
		if(retirerGroupeTousCours==null)
			retirerGroupeTousCours = conn.prepareStatement("DELETE FROM cours_groupes WHERE id_groupe=?");
		
		retirerGroupeTousCours.setInt(1,groupe.getId());
		retirerGroupeTousCours.executeUpdate();
		
		//supprimer tous les étudiants du groupe
		if(retirerGroupeTousEtudiants==null)
			retirerGroupeTousEtudiants = conn.prepareStatement("DELETE FROM groupes_etudiants WHERE id_groupe=?");
		
		retirerGroupeTousEtudiants.setInt(1,groupe.getId());
		retirerGroupeTousEtudiants.executeUpdate();
		
		//supprimer le groupe
		if(supprimerGroupe==null)
			supprimerGroupe = conn.prepareStatement("DELETE FROM groupes WHERE id_groupe=?");
		
		supprimerGroupe.setInt(1,groupe.getId());
		supprimerGroupe.executeUpdate();
	}

	@Override
	public List<Groupe> listerGroupes() throws SQLException {
		if(listeGroupes==null)
			listeGroupes = conn.prepareStatement("SELECT id_groupe,nom_groupe,code_ue FROM groupes");
		
		List<Groupe> grps = new ArrayList<Groupe>(20);
		
		ResultSet rs = listeGroupes.executeQuery();
		while(rs.next()){
			Groupe grp = new Groupe();
			
			grp.setId(rs.getInt(1));
			grp.setNom(rs.getString(2));
			grp.setCodeUe(rs.getString(3));
			
			grps.add(grp);
		}
		rs.close();
		return grps;
	}

	@Override
	public void ajouterGroupeAuCours(Groupe groupe, Cours cours) throws SQLException {
		if(ajouterGroupeAuCours==null)
			ajouterGroupeAuCours = conn.prepareStatement("INSERT INTO cours_groupes (id_groupe,id_cours) VALUES (?,?)");
		
		ajouterGroupeAuCours.setInt(1,groupe.getId());
		ajouterGroupeAuCours.setInt(2, cours.getId());
		
		ajouterGroupeAuCours.executeUpdate();
	}

	@Override
	public void retirerGroupeDeCours(Groupe groupe, Cours cours) throws SQLException {
		if(retirerGroupeDeCours==null)
			retirerGroupeDeCours = conn.prepareStatement("DELETE FROM cours_groupes WHERE id_groupe=? AND id_cours=?");
		
		retirerGroupeDeCours.setInt(1,groupe.getId());
		retirerGroupeDeCours.setInt(2, cours.getId());
		
		retirerGroupeDeCours.executeUpdate();
	}

	@Override
	public List<Groupe> listerGroupesDeCours(Cours cours) throws SQLException {
		if(listerGroupesDeCours==null)
			listerGroupesDeCours = conn.prepareStatement("SELECT groupes.id_groupe,groupes.nom_groupe,groupes.code_ue FROM groupes JOIN cours_groupes ON groupes.id_groupe=cours_groupes.id_groupe WHERE cours_groupes.id_cours=?");
		
		List<Groupe> grps = new ArrayList<Groupe>(20);
		
		listerGroupesDeCours.setInt(1, cours.getId());
		
		ResultSet rs = listerGroupesDeCours.executeQuery();
		while(rs.next()){
			Groupe grp = new Groupe();
			
			grp.setId(rs.getInt(1));
			grp.setNom(rs.getString(2));
			grp.setCodeUe(rs.getString(3));
			
			grps.add(grp);
		}
		rs.close();
		return grps;
	}

	@Override
	public List<Cours> listerCoursDeGroupe(Groupe groupe) throws SQLException {
		if(listerCoursDeGroupe==null)
			listerCoursDeGroupe = conn.prepareStatement("SELECT cours.id_cours,cours.type_cours,cours.code_ue,cours.id_enseignant,cours.creneau_cours,cours.salle FROM cours JOIN cours_groupes ON cours.id_cours=cours_groupes.id_cours WHERE cours_groupes.id_groupe=?");
		
		List<Cours> courss = new ArrayList<Cours>(20);
		
		listerCoursDeGroupe.setInt(1, groupe.getId());
		
		ResultSet rs = listerCoursDeGroupe.executeQuery();
		while(rs.next()){
			Cours cours = new Cours();
			
			cours.setId(rs.getInt(1));
			cours.setType(rs.getString(2));
			cours.setCodeUe(rs.getString(3));
			cours.setIdEnseignant(rs.getInt(4));
			cours.setCreneau(rs.getInt(5));
			cours.setSalle(rs.getString(6));
			
			courss.add(cours);
		}
		rs.close();
		return courss;
	}

	@Override
	public void ajouterEtudiantAuGroupe(Etudiant etudiant, Groupe groupe) throws SQLException {
		if(ajouterEtudiantAuGroupe==null)
			ajouterEtudiantAuGroupe = conn.prepareStatement("INSERT INTO groupes_etudiants (numero_etudiant,id_groupe) VALUES (?,?)");
		
		ajouterEtudiantAuGroupe.setInt(1, etudiant.getNumero());
		ajouterEtudiantAuGroupe.setInt(2, groupe.getId());
		
		ajouterEtudiantAuGroupe.executeUpdate();

	}

	@Override
	public void retirerEtudiantDeGroupe(Etudiant etudiant, Groupe groupe) throws SQLException {
		if(retirerEtudiantDeGroupe==null)
			retirerEtudiantDeGroupe = conn.prepareStatement("DELETE FROM groupes_etudiants WHERE numero_etudiant=? AND id_groupe=?");
		
		retirerEtudiantDeGroupe.setInt(1, etudiant.getNumero());
		retirerEtudiantDeGroupe.setInt(2, groupe.getId());
		
		retirerEtudiantDeGroupe.executeUpdate();

	}

	@Override
	public List<Etudiant> listerEtudiantsDeGroupe(Groupe groupe) throws SQLException {
		List<Etudiant> etus = new ArrayList<Etudiant>();
		if (listerEtudiantsDeGroupe == null)
			listerEtudiantsDeGroupe = conn
					.prepareStatement("SELECT etudiants.numero_etudiant,etudiants.nom_etudiant,etudiants.prenom_etudiant FROM etudiants JOIN groupes_etudiants ON groupes_etudiants.numero_etudiant=etudiants.numero_etudiant WHERE groupes_etudiants.id_groupe=?");

		listerEtudiantsDeGroupe.setInt(1, groupe.getId());
		
		ResultSet rs = listerEtudiantsDeGroupe.executeQuery();
		while (rs.next()) {
			Etudiant etu = new Etudiant();
			etu.setNumero(rs.getInt(1));
			etu.setNom(rs.getString(2));
			etu.setPrenom(rs.getString(3));
			etus.add(etu);
		}
		rs.close();
		return etus;
	}

	@Override
	public List<Groupe> listerGroupesEtudiant(Etudiant etudiant) throws SQLException {
		if(listerGroupesEtudiant==null)
			listerGroupesEtudiant = conn.prepareStatement("SELECT groupes.id_groupe,groupes.nom_groupe,groupes.code_ue FROM groupes JOIN groupes_etudiants ON groupes.id_groupe=groupes_etudiants.id_groupe WHERE groupes_etudiants.numero_etudiant=?");
				
		List<Groupe> grps = new ArrayList<Groupe>(20);
		
		listerGroupesEtudiant.setInt(1, etudiant.getNumero());
		
		ResultSet rs = listerGroupesEtudiant.executeQuery();
		while(rs.next()){
			Groupe grp = new Groupe();
			
			grp.setId(rs.getInt(1));
			grp.setNom(rs.getString(2));
			grp.setCodeUe(rs.getString(3));
			
			grps.add(grp);
		}
		rs.close();
		return grps;
	}
	
	@Override
	public List<Groupe> listerGroupeDeUe(Ue ue)throws SQLException{
		if(listerGroupeDeUe==null)
			listerGroupeDeUe=conn.prepareStatement("SELECT id_groupe,nom_groupe,code_ue FROM groupes WHERE code_ue=?");

		List<Groupe> grps = new ArrayList<Groupe>(8);
		listerGroupeDeUe.setString(1, ue.getCode());
		ResultSet rs = listerGroupeDeUe.executeQuery();
		while(rs.next()){
			Groupe grp = new Groupe();
			grp.setId(rs.getInt(1));
			grp.setNom(rs.getString(2));
			grp.setCodeUe(rs.getString(3));
			
			grps.add(grp);
		}
		rs.close();
		return grps;
	}

	@Override
	public void close() throws SQLException {
		if(conn.getAutoCommit()==false)
			conn.commit();
		conn.close();
		
	}



	@Override
	public Enseignant enseignantDeCours(Cours cours) throws SQLException {
		if(enseignantDeCours==null)
			enseignantDeCours = conn.prepareStatement("SELECT id_enseignant,nom_enseignant,prenom_enseignant,disponibilite_enseignant FROM enseignants WHERE id_enseignant=?");
		
		enseignantDeCours.setInt(1, cours.getIdEnseignant());
		ResultSet rs = enseignantDeCours.executeQuery();
		
		Enseignant enseignant = null;
		
		if(rs.next()){
			enseignant = new Enseignant();
			enseignant.setId(rs.getInt(1));
			enseignant.setNom(rs.getString(2));
			enseignant.setPrenom(rs.getString(3));
			enseignant.setDisponibilite(rs.getString(4).toCharArray());
		}
		rs.close();
		return enseignant;
	}

	@Override
	public List<Cours> listerCoursEnseignant(Enseignant enseignant)
			throws SQLException {
		if(listerCoursEnseignant==null)
			listerCoursEnseignant=conn.prepareStatement("SELECT id_cours,type_cours,code_ue,id_enseignant,creneau_cours FROM cours WHERE id_enseignant=?");
		
		listerCoursEnseignant.setInt(1, enseignant.getId());
		
		List<Cours> courss = new ArrayList<Cours>(10);
		ResultSet rs = listerCoursEnseignant.executeQuery();
		
		while (rs.next()) {
			Cours cours = new Cours();
			cours.setId(rs.getInt(1));
			cours.setType(rs.getString(2));
			cours.setCodeUe(rs.getString(3));
			cours.setIdEnseignant(rs.getInt(4));
			cours.setCreneau(rs.getInt(5));
			courss.add(cours);
		}
		rs.close();
		return courss;
	}
	
	
	@Override
	public AccumulateurErreur rechercherErreurs() throws SQLException {
		AccumulateurErreur accumulateur = new AccumulateurErreur();
		verifierCours(accumulateur);
		verifierGroupes(accumulateur);
		verifierEtudiants(accumulateur);
		verifierEnseignants(accumulateur);
		return accumulateur;
	}

	
	
	

	private void verifierGroupes(AccumulateurErreur accumulateur) throws SQLException {
		//vérifier que chaque groupe a au moins 1 étudiant
		List<Groupe> groupes = listerGroupes();
		for (Groupe groupe : groupes) {
			List<Etudiant> etus = listerEtudiantsDeGroupe(groupe);
			if(etus.size()==0){
				accumulateur.ajouterAvertissement("Aucun étudiant dans le groupe "+groupe.getNom()+ " de l'UE "+ groupe.getCodeUe()+".");
			}
		}
	}

	private void verifierEnseignants(AccumulateurErreur accumulateur) throws SQLException {
		List<Enseignant> enseignants = listerEnseignant();
		for (Enseignant enseignant : enseignants) {
			List<Cours> lescours = listerCoursEnseignant(enseignant);

			//préparation d'une Map pour y mettre les cours de l'enseignant par créneau
			Map<Integer,ArrayList<Cours>> coursParCreneau = new HashMap<Integer,ArrayList<Cours>>();
			for(int i=1;i<=20;i++){
				coursParCreneau.put(i, new ArrayList<Cours>());
			}
			
			for (Cours cours : lescours) {
				if(cours.getCreneau()>0){
					if(enseignant.getDisponibilite()[cours.getCreneau()-1]!='T'){
						accumulateur.ajouterErreur("L'enseignant n'est pas disponible pour le cours de l'UE "+cours.getCodeUe()+" du créneau du "+CreneauFormater.format(cours.getCreneau()));
					}
					coursParCreneau.get(cours.getCreneau()).add(cours);
				}
			}
			
			for(int i=1;i<=20;i++){//pour chaque créneau
				ArrayList<Cours> coursDuCreneau =  coursParCreneau.get(i);
				if(coursDuCreneau.size()>1){//plusieurs cours en même temps
					//formatage message erreur
					StringBuffer buffer = new StringBuffer();
					buffer.append("Conflit pour l'enseignant ").append(enseignant.getNom()).append(" ").append(enseignant.getPrenom()).append(" pour le créneau du ").append(CreneauFormater.format(i)).append(" : ");
					for(int y=0;y<coursDuCreneau.size();y++){
						buffer.append(coursDuCreneau.get(y).getType()).append(" de ").append(coursDuCreneau.get(y).getCodeUe());
						
						if(y==coursDuCreneau.size()-1)
							buffer.append(".");
						else
							buffer.append(", ");
					}
					accumulateur.ajouterErreur(buffer.toString());
				}
			}
		}
	}

	private void verifierEtudiants(AccumulateurErreur accumulateur) throws SQLException  {
		List<Etudiant> etudiants = listerEtudiants();
		for (Etudiant etudiant : etudiants) {
			//on vérifie que les étudiants sont bien dans un groupe par UE
			List<Ue> uesEtudiants = listerUesEtudiant(etudiant);
			List<Groupe> groupesEtudiants = listerGroupesEtudiant(etudiant);
			for (Ue ue : uesEtudiants) {
				//pour chaque UE, on doit trouver un groupe
				int nbGroupesUe = 0;
				for (Groupe groupe : groupesEtudiants) {
					if(groupe.getCodeUe().equals(ue.getCode()))
						nbGroupesUe++;
				}
				if(nbGroupesUe==0){
					accumulateur.ajouterAvertissement("L'étudiant n°"+etudiant.getNumero()+" ("+etudiant.getNom()+" "+etudiant.getPrenom()+") n'est dans aucun groupe pour l'UE "+ue.getCode()+ "("+ue.getLibelle()+")");
				}
				if(nbGroupesUe>1){
					accumulateur.ajouterAvertissement("L'étudiant n°"+etudiant.getNumero()+" ("+etudiant.getNom()+" "+etudiant.getPrenom()+") est dans "+nbGroupesUe+" groupes pour l'UE "+ue.getCode()+ "("+ue.getLibelle()+")");
				}
			}
			
			//on vérifie que tous les cours sont à des heures differentes//
			
			//préparation d'une Map pour y mettre les cours de l'étudiant par créneau
			Map<Integer,ArrayList<GroupeCoursPair>> coursParCreneau = new HashMap<Integer,ArrayList<GroupeCoursPair>>();
			for(int i=1;i<=20;i++){
				coursParCreneau.put(i, new ArrayList<GroupeCoursPair>());
			}
			//on récupère les groupes puis les cours de l'étudiant
			for (Groupe groupe : groupesEtudiants) {
				List<Cours> lescours = listerCoursDeGroupe(groupe);
				for (Cours cours : lescours) {
					if(cours.getCreneau()>0){
						GroupeCoursPair pair = new GroupeCoursPair();
						pair.cours = cours;
						pair.groupe = groupe;
						coursParCreneau.get(cours.getCreneau()).add(pair);
					}
						
				}
			}
			for(int i=1;i<=20;i++){//pour chaque créneau
				ArrayList<GroupeCoursPair> coursDuCreneau =  coursParCreneau.get(i);
				if(coursDuCreneau.size()>1){//a on plusieurs cours?
					//formatage message erreur
					StringBuffer buffer = new StringBuffer();
					buffer.append("Conflit pour l'étudiant n°").append(etudiant.getNumero()).append(" (").append(etudiant.getNom()).append(" ").append(etudiant.getPrenom()).append(") pour le créneau du ").append(CreneauFormater.format(i)).append(" : ");
					for(int y=0;y<coursDuCreneau.size();y++){
						buffer.append(coursDuCreneau.get(y).cours.getCodeUe()).append(" ").append(coursDuCreneau.get(y).groupe.getNom());
						if(y==coursDuCreneau.size()-1)
							buffer.append(".");
						else
							buffer.append(", ");
					}
					accumulateur.ajouterErreur(buffer.toString());
				}
			}
		}
	}

	private void verifierCours(AccumulateurErreur accumulateur) throws SQLException {
		List<Cours> lescours = listerCours();
		for (Cours cours : lescours) {
			if(cours.getCreneau()==0){
				//erreur cours pas programmé
				accumulateur.ajouterErreur("Le cours de type \"" + cours.getType()+"\" de l'UE "+cours.getCodeUe()+" n'a pas de créneau horraire.");
			}
			if(cours.getIdEnseignant()==0){
				//pas d'enseignant
				accumulateur.ajouterAvertissement("Le cours de type \"" + cours.getType()+"\" de l'UE "+cours.getCodeUe()+" n'a pas d'enseignant : impossible de vérifier la disponibilité de l'enseignant.");
			}
			//vérifier qu'on a au moins un groupe à chaque cours
			List<Groupe> groupes = listerGroupesDeCours(cours);
			if(groupes.size()==0){
				accumulateur.ajouterAvertissement("Aucun groupe inscrit au cours de type \"" + cours.getType()+"\" de l'UE "+cours.getCodeUe()+".");
			}
		}
	}
	
	private class GroupeCoursPair{
		public Groupe groupe;
		public Cours cours;
	}

	@Override
	public void modifierCreneauCours(int idCours, int creneau) throws SQLException {
		if (modifierCreneauCours == null) {
			modifierCreneauCours = conn
					.prepareStatement("UPDATE cours SET creneau_cours=? WHERE id_cours=?");
		}
		modifierCreneauCours.setInt(1, creneau);
		modifierCreneauCours.setInt(2,idCours);

		modifierCreneauCours.executeUpdate();
		
	}

	@Override
	public Ue chargerUe(String codeUe) throws SQLException {
		if (chargerUe == null)
			chargerUe = conn
					.prepareStatement("SELECT code_ue,libele_ue FROM ues WHERE code_ue=?");
		chargerUe.setString(1, codeUe);
		ResultSet rs = chargerUe.executeQuery();
		if (rs.next()) {
			Ue ue = new Ue();
			ue.setCode(rs.getString(1));
			ue.setLibelle(rs.getString(2));
			rs.close();
			return ue;
		}
		rs.close();
		return null;
	}
}
